1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.collect;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkElementIndex;
21 import static com.google.common.base.Preconditions.checkNotNull;
22
23 import com.google.common.annotations.Beta;
24 import com.google.common.annotations.GwtCompatible;
25 import com.google.common.base.Objects;
26
27 import java.io.Serializable;
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34
35 import javax.annotation.Nullable;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 @Beta
83 @GwtCompatible(emulated = true)
84 public final class ArrayTable<R, C, V> extends AbstractTable<R, C, V> implements Serializable {
85
86
87
88
89
90
91
92
93
94
95 public static <R, C, V> ArrayTable<R, C, V> create(
96 Iterable<? extends R> rowKeys, Iterable<? extends C> columnKeys) {
97 return new ArrayTable<R, C, V>(rowKeys, columnKeys);
98 }
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128 public static <R, C, V> ArrayTable<R, C, V> create(Table<R, C, V> table) {
129 return (table instanceof ArrayTable<?, ?, ?>)
130 ? new ArrayTable<R, C, V>((ArrayTable<R, C, V>) table)
131 : new ArrayTable<R, C, V>(table);
132 }
133
134 private final ImmutableList<R> rowList;
135 private final ImmutableList<C> columnList;
136
137
138 private final ImmutableMap<R, Integer> rowKeyToIndex;
139 private final ImmutableMap<C, Integer> columnKeyToIndex;
140 private final V[][] array;
141
142 private ArrayTable(Iterable<? extends R> rowKeys,
143 Iterable<? extends C> columnKeys) {
144 this.rowList = ImmutableList.copyOf(rowKeys);
145 this.columnList = ImmutableList.copyOf(columnKeys);
146 checkArgument(!rowList.isEmpty());
147 checkArgument(!columnList.isEmpty());
148
149
150
151
152
153
154 rowKeyToIndex = index(rowList);
155 columnKeyToIndex = index(columnList);
156
157 @SuppressWarnings("unchecked")
158 V[][] tmpArray
159 = (V[][]) new Object[rowList.size()][columnList.size()];
160 array = tmpArray;
161
162 eraseAll();
163 }
164
165 private static <E> ImmutableMap<E, Integer> index(List<E> list) {
166 ImmutableMap.Builder<E, Integer> columnBuilder = ImmutableMap.builder();
167 for (int i = 0; i < list.size(); i++) {
168 columnBuilder.put(list.get(i), i);
169 }
170 return columnBuilder.build();
171 }
172
173 private ArrayTable(Table<R, C, V> table) {
174 this(table.rowKeySet(), table.columnKeySet());
175 putAll(table);
176 }
177
178 private ArrayTable(ArrayTable<R, C, V> table) {
179 rowList = table.rowList;
180 columnList = table.columnList;
181 rowKeyToIndex = table.rowKeyToIndex;
182 columnKeyToIndex = table.columnKeyToIndex;
183 @SuppressWarnings("unchecked")
184 V[][] copy = (V[][]) new Object[rowList.size()][columnList.size()];
185 array = copy;
186
187 eraseAll();
188 for (int i = 0; i < rowList.size(); i++) {
189 System.arraycopy(table.array[i], 0, copy[i], 0, table.array[i].length);
190 }
191 }
192
193 private abstract static class ArrayMap<K, V> extends Maps.ImprovedAbstractMap<K, V> {
194 private final ImmutableMap<K, Integer> keyIndex;
195
196 private ArrayMap(ImmutableMap<K, Integer> keyIndex) {
197 this.keyIndex = keyIndex;
198 }
199
200 @Override
201 public Set<K> keySet() {
202 return keyIndex.keySet();
203 }
204
205 K getKey(int index) {
206 return keyIndex.keySet().asList().get(index);
207 }
208
209 abstract String getKeyRole();
210
211 @Nullable abstract V getValue(int index);
212
213 @Nullable abstract V setValue(int index, V newValue);
214
215 @Override
216 public int size() {
217 return keyIndex.size();
218 }
219
220 @Override
221 public boolean isEmpty() {
222 return keyIndex.isEmpty();
223 }
224
225 @Override
226 protected Set<Entry<K, V>> createEntrySet() {
227 return new Maps.EntrySet<K, V>() {
228 @Override
229 Map<K, V> map() {
230 return ArrayMap.this;
231 }
232
233 @Override
234 public Iterator<Entry<K, V>> iterator() {
235 return new AbstractIndexedListIterator<Entry<K, V>>(size()) {
236 @Override
237 protected Entry<K, V> get(final int index) {
238 return new AbstractMapEntry<K, V>() {
239 @Override
240 public K getKey() {
241 return ArrayMap.this.getKey(index);
242 }
243
244 @Override
245 public V getValue() {
246 return ArrayMap.this.getValue(index);
247 }
248
249 @Override
250 public V setValue(V value) {
251 return ArrayMap.this.setValue(index, value);
252 }
253 };
254 }
255 };
256 }
257 };
258 }
259
260
261
262 @Override
263 public boolean containsKey(@Nullable Object key) {
264 return keyIndex.containsKey(key);
265 }
266
267 @Override
268 public V get(@Nullable Object key) {
269 Integer index = keyIndex.get(key);
270 if (index == null) {
271 return null;
272 } else {
273 return getValue(index);
274 }
275 }
276
277 @Override
278 public V put(K key, V value) {
279 Integer index = keyIndex.get(key);
280 if (index == null) {
281 throw new IllegalArgumentException(
282 getKeyRole() + " " + key + " not in " + keyIndex.keySet());
283 }
284 return setValue(index, value);
285 }
286
287 @Override
288 public V remove(Object key) {
289 throw new UnsupportedOperationException();
290 }
291
292 @Override
293 public void clear() {
294 throw new UnsupportedOperationException();
295 }
296 }
297
298
299
300
301
302 public ImmutableList<R> rowKeyList() {
303 return rowList;
304 }
305
306
307
308
309
310 public ImmutableList<C> columnKeyList() {
311 return columnList;
312 }
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328 public V at(int rowIndex, int columnIndex) {
329
330 checkElementIndex(rowIndex, rowList.size());
331 checkElementIndex(columnIndex, columnList.size());
332 return array[rowIndex][columnIndex];
333 }
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350 public V set(int rowIndex, int columnIndex, @Nullable V value) {
351
352 checkElementIndex(rowIndex, rowList.size());
353 checkElementIndex(columnIndex, columnList.size());
354 V oldValue = array[rowIndex][columnIndex];
355 array[rowIndex][columnIndex] = value;
356 return oldValue;
357 }
358
359
360
361
362
363
364
365 @Override
366 @Deprecated public void clear() {
367 throw new UnsupportedOperationException();
368 }
369
370
371
372
373
374 public void eraseAll() {
375 for (V[] row : array) {
376 Arrays.fill(row, null);
377 }
378 }
379
380
381
382
383
384 @Override
385 public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) {
386 return containsRow(rowKey) && containsColumn(columnKey);
387 }
388
389
390
391
392
393 @Override
394 public boolean containsColumn(@Nullable Object columnKey) {
395 return columnKeyToIndex.containsKey(columnKey);
396 }
397
398
399
400
401
402 @Override
403 public boolean containsRow(@Nullable Object rowKey) {
404 return rowKeyToIndex.containsKey(rowKey);
405 }
406
407 @Override
408 public boolean containsValue(@Nullable Object value) {
409 for (V[] row : array) {
410 for (V element : row) {
411 if (Objects.equal(value, element)) {
412 return true;
413 }
414 }
415 }
416 return false;
417 }
418
419 @Override
420 public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
421 Integer rowIndex = rowKeyToIndex.get(rowKey);
422 Integer columnIndex = columnKeyToIndex.get(columnKey);
423 return (rowIndex == null || columnIndex == null)
424 ? null : at(rowIndex, columnIndex);
425 }
426
427
428
429
430 @Override
431 public boolean isEmpty() {
432 return false;
433 }
434
435
436
437
438
439
440
441 @Override
442 public V put(R rowKey, C columnKey, @Nullable V value) {
443 checkNotNull(rowKey);
444 checkNotNull(columnKey);
445 Integer rowIndex = rowKeyToIndex.get(rowKey);
446 checkArgument(rowIndex != null, "Row %s not in %s", rowKey, rowList);
447 Integer columnIndex = columnKeyToIndex.get(columnKey);
448 checkArgument(columnIndex != null,
449 "Column %s not in %s", columnKey, columnList);
450 return set(rowIndex, columnIndex, value);
451 }
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469 @Override
470 public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
471 super.putAll(table);
472 }
473
474
475
476
477
478
479
480 @Override
481 @Deprecated public V remove(Object rowKey, Object columnKey) {
482 throw new UnsupportedOperationException();
483 }
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498 public V erase(@Nullable Object rowKey, @Nullable Object columnKey) {
499 Integer rowIndex = rowKeyToIndex.get(rowKey);
500 Integer columnIndex = columnKeyToIndex.get(columnKey);
501 if (rowIndex == null || columnIndex == null) {
502 return null;
503 }
504 return set(rowIndex, columnIndex, null);
505 }
506
507
508
509 @Override
510 public int size() {
511 return rowList.size() * columnList.size();
512 }
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527 @Override
528 public Set<Cell<R, C, V>> cellSet() {
529 return super.cellSet();
530 }
531
532 @Override
533 Iterator<Cell<R, C, V>> cellIterator() {
534 return new AbstractIndexedListIterator<Cell<R, C, V>>(size()) {
535 @Override protected Cell<R, C, V> get(final int index) {
536 return new Tables.AbstractCell<R, C, V>() {
537 final int rowIndex = index / columnList.size();
538 final int columnIndex = index % columnList.size();
539 @Override
540 public R getRowKey() {
541 return rowList.get(rowIndex);
542 }
543 @Override
544 public C getColumnKey() {
545 return columnList.get(columnIndex);
546 }
547 @Override
548 public V getValue() {
549 return at(rowIndex, columnIndex);
550 }
551 };
552 }
553 };
554 }
555
556
557
558
559
560
561
562
563
564
565
566
567
568 @Override
569 public Map<R, V> column(C columnKey) {
570 checkNotNull(columnKey);
571 Integer columnIndex = columnKeyToIndex.get(columnKey);
572 return (columnIndex == null)
573 ? ImmutableMap.<R, V>of() : new Column(columnIndex);
574 }
575
576 private class Column extends ArrayMap<R, V> {
577 final int columnIndex;
578
579 Column(int columnIndex) {
580 super(rowKeyToIndex);
581 this.columnIndex = columnIndex;
582 }
583
584 @Override
585 String getKeyRole() {
586 return "Row";
587 }
588
589 @Override
590 V getValue(int index) {
591 return at(index, columnIndex);
592 }
593
594 @Override
595 V setValue(int index, V newValue) {
596 return set(index, columnIndex, newValue);
597 }
598 }
599
600
601
602
603
604
605
606 @Override
607 public ImmutableSet<C> columnKeySet() {
608 return columnKeyToIndex.keySet();
609 }
610
611 private transient ColumnMap columnMap;
612
613 @Override
614 public Map<C, Map<R, V>> columnMap() {
615 ColumnMap map = columnMap;
616 return (map == null) ? columnMap = new ColumnMap() : map;
617 }
618
619 private class ColumnMap extends ArrayMap<C, Map<R, V>> {
620 private ColumnMap() {
621 super(columnKeyToIndex);
622 }
623
624 @Override
625 String getKeyRole() {
626 return "Column";
627 }
628
629 @Override
630 Map<R, V> getValue(int index) {
631 return new Column(index);
632 }
633
634 @Override
635 Map<R, V> setValue(int index, Map<R, V> newValue) {
636 throw new UnsupportedOperationException();
637 }
638
639 @Override
640 public Map<R, V> put(C key, Map<R, V> value) {
641 throw new UnsupportedOperationException();
642 }
643 }
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658 @Override
659 public Map<C, V> row(R rowKey) {
660 checkNotNull(rowKey);
661 Integer rowIndex = rowKeyToIndex.get(rowKey);
662 return (rowIndex == null) ? ImmutableMap.<C, V>of() : new Row(rowIndex);
663 }
664
665 private class Row extends ArrayMap<C, V> {
666 final int rowIndex;
667
668 Row(int rowIndex) {
669 super(columnKeyToIndex);
670 this.rowIndex = rowIndex;
671 }
672
673 @Override
674 String getKeyRole() {
675 return "Column";
676 }
677
678 @Override
679 V getValue(int index) {
680 return at(rowIndex, index);
681 }
682
683 @Override
684 V setValue(int index, V newValue) {
685 return set(rowIndex, index, newValue);
686 }
687 }
688
689
690
691
692
693
694
695 @Override
696 public ImmutableSet<R> rowKeySet() {
697 return rowKeyToIndex.keySet();
698 }
699
700 private transient RowMap rowMap;
701
702 @Override
703 public Map<R, Map<C, V>> rowMap() {
704 RowMap map = rowMap;
705 return (map == null) ? rowMap = new RowMap() : map;
706 }
707
708 private class RowMap extends ArrayMap<R, Map<C, V>> {
709 private RowMap() {
710 super(rowKeyToIndex);
711 }
712
713 @Override
714 String getKeyRole() {
715 return "Row";
716 }
717
718 @Override
719 Map<C, V> getValue(int index) {
720 return new Row(index);
721 }
722
723 @Override
724 Map<C, V> setValue(int index, Map<C, V> newValue) {
725 throw new UnsupportedOperationException();
726 }
727
728 @Override
729 public Map<C, V> put(R key, Map<C, V> value) {
730 throw new UnsupportedOperationException();
731 }
732 }
733
734
735
736
737
738
739
740
741
742
743 @Override
744 public Collection<V> values() {
745 return super.values();
746 }
747
748 private static final long serialVersionUID = 0;
749 }